﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using ASCII.Common;
using PlayDeezGames.Common;
using System.Windows.Threading;

namespace ASCII.ClickTheYellowBox
{
    public class CTYBPlayState : CTYBStateBase
    {
        WeightedGenerator<ASCIICell> generator = new WeightedGenerator<ASCIICell>();

        public CTYBPlayState(ASCIIRenderer theRenderer)
            : base(theRenderer)
        {
            timer.Interval = new TimeSpan(0, 0, 1);
            timer.Tick += new EventHandler(timer_Tick);

            generator[new ASCIICell(0x18, ASCIICellColor.Cyan, ASCIICellColor.Black)] = 5;
            generator[new ASCIICell(0x19, ASCIICellColor.Cyan, ASCIICellColor.Black)] = 5;
            generator[new ASCIICell(0xac, ASCIICellColor.Cyan, ASCIICellColor.Black)] = 10;
            generator[new ASCIICell(0xab, ASCIICellColor.Cyan, ASCIICellColor.Black)] = 5;
            generator[new ASCIICell(0x30, ASCIICellColor.Cyan, ASCIICellColor.Black)] = 10;
            generator[new ASCIICell(0x32, ASCIICellColor.Cyan, ASCIICellColor.Black)] = 2;
            generator[new ASCIICell(0x34, ASCIICellColor.Cyan, ASCIICellColor.Black)] = 1;

            generator[new ASCIICell(0x18, ASCIICellColor.Green, ASCIICellColor.Black)] = 5;
            generator[new ASCIICell(0x19, ASCIICellColor.Green, ASCIICellColor.Black)] = 5;
            generator[new ASCIICell(0xac, ASCIICellColor.Green, ASCIICellColor.Black)] = 10;
            generator[new ASCIICell(0xab, ASCIICellColor.Green, ASCIICellColor.Black)] = 5;
            generator[new ASCIICell(0x30, ASCIICellColor.Green, ASCIICellColor.Black)] = 10;
            generator[new ASCIICell(0x32, ASCIICellColor.Green, ASCIICellColor.Black)] = 2;
            generator[new ASCIICell(0x34, ASCIICellColor.Green, ASCIICellColor.Black)] = 1;

            generator[new ASCIICell(0x18, ASCIICellColor.Red, ASCIICellColor.Black)] = 20;
            generator[new ASCIICell(0x19, ASCIICellColor.Red, ASCIICellColor.Black)] = 20;
            generator[new ASCIICell(0xac, ASCIICellColor.Red, ASCIICellColor.Black)] = 1;
            generator[new ASCIICell(0xab, ASCIICellColor.Red, ASCIICellColor.Black)] = 2;
            generator[new ASCIICell(0x30, ASCIICellColor.Red, ASCIICellColor.Black)] = 1;
            generator[new ASCIICell(0x32, ASCIICellColor.Red, ASCIICellColor.Black)] = 5;
            generator[new ASCIICell(0x34, ASCIICellColor.Red, ASCIICellColor.Black)] = 10;

            generator[new ASCIICell(0, ASCIICellColor.Black, ASCIICellColor.Black)] = 100;
        }

        private void ChangeTime(int delta)
        {
            time += delta;
            if (gameover)
            {
                Finish();
                Parent.OnMessage(new MessageBase(StateMachine<CTYBState>.MSGID_Step));
            }
            ShowStats();
            OnDraw();
        }

        private void timer_Tick(object sender, EventArgs e)
        {
            actualTime++;
            ChangeTime(-1);
        }

        private int actualTime = 0;
        private int actualHits = 0;
        private int actualMisses = 0;
        private int time=60;
        private int hits=0;
        private int misses=0;
        private int score
        {
            get
            {
                int theScore = hits * 10 - misses * 15;
                return theScore>0?theScore:0;
            }
        }
        private bool gameover
        {
            get
            {
                return time < 1;
            }
        }
        private DispatcherTimer timer = new DispatcherTimer();
        private Random random = new Random();

        private void PutBox()
        {
            Renderer.SetCells(1, 1, Renderer.GridBoard.Rows - 2, Renderer.GridBoard.Rows - 2, 0, ASCIICellColor.Black, ASCIICellColor.Black);
            int x = random.Next(1, Renderer.GridBoard.Rows - 1);
            int y = random.Next(1, Renderer.GridBoard.Rows - 1);
            ASCIICell cell = generator.Generate(new RandomNumberGenerator());
            Renderer.Board[x][y].CopyFrom(cell);

            x = random.Next(1, Renderer.GridBoard.Rows - 1);
            y = random.Next(1, Renderer.GridBoard.Rows - 1);
            Renderer.SetCell(x, y, 219, ASCIICellColor.Yellow);
        }

        private void ShowStats()
        {
            Renderer.WriteText(Renderer.GridBoard.Rows + 1, 2, string.Format("{0,8}", time), ASCIICellColor.Cyan, ASCIICellColor.DarkGray);
            Renderer.WriteText(Renderer.GridBoard.Rows + 1, 5, string.Format("{0,8}", hits), ASCIICellColor.Green, ASCIICellColor.DarkGray);
            Renderer.WriteText(Renderer.GridBoard.Rows + 1, 8, string.Format("{0,8}", misses), ASCIICellColor.Red, ASCIICellColor.DarkGray);
            Renderer.WriteText(Renderer.GridBoard.Rows + 1, 11, string.Format("{0,8}", score), ASCIICellColor.White, ASCIICellColor.DarkGray);
        }


        protected override void OnStart()
        {
            timer.Stop();
            time = 60;
            hits = 0;
            misses = 0;
            Renderer.SetCells(0, 0, Renderer.GridBoard.Columns, Renderer.GridBoard.Rows, 0, ASCIICellColor.Black, ASCIICellColor.Black);
            Renderer.DrawTable(TableDrawingPalette.V2H2Palette, new int[] { 0, Renderer.GridBoard.Rows - 1}, new int[] { 0, Renderer.GridBoard.Rows - 1 }, ASCIICellColor.Blue, ASCIICellColor.DarkGray, false);
            Renderer.DrawTable(TableDrawingPalette.V2H2Palette, new int[] { Renderer.GridBoard.Rows ,Renderer.GridBoard.Columns-1 }, new int[] { 0, 3,6,9,12, Renderer.GridBoard.Rows - 1 }, ASCIICellColor.Blue, ASCIICellColor.DarkGray, true);
            Renderer.WriteText(Renderer.GridBoard.Rows + 1, 1, "Time:", ASCIICellColor.Cyan, ASCIICellColor.DarkGray);
            Renderer.WriteText(Renderer.GridBoard.Rows + 1, 4, "Hits:", ASCIICellColor.Green, ASCIICellColor.DarkGray);
            Renderer.WriteText(Renderer.GridBoard.Rows + 1, 7, "Misses:", ASCIICellColor.Red, ASCIICellColor.DarkGray);
            Renderer.WriteText(Renderer.GridBoard.Rows + 1, 10, "Score:", ASCIICellColor.White, ASCIICellColor.DarkGray);
            ShowStats();
            PutBox();
        }

        protected override void OnIdle()
        {

        }

        protected override void OnFinish()
        {
            ExitState = CTYBState.GameOver;
            timer.Stop();
        }

        private void OnDraw()
        {
            Renderer.Render();
        }

        private void RecordHit()
        {
            actualHits++;
            hits++;
            ShowStats();
            PutBox();
            OnDraw();
        }

        private void RecordMiss()
        {
            actualMisses++;
            misses++;
            ShowStats();
            PutBox();
            OnDraw();
        }

        private bool OnMouseDown(MouseButtonEventArgs e)
        {
            if (gameover) return true;

            if (!timer.IsEnabled)
            {
                actualTime = 0;
                actualHits = 0;
                actualMisses = 0;
                timer.Start();
            }
            int column = Renderer.GetMouseColumn(null, e);
            int row = Renderer.GetMouseRow(null, e);
            if (column > 0 && row > 0 && column < Renderer.GridBoard.Rows - 1 && column < Renderer.GridBoard.Rows - 1)
            {
                switch (Renderer.Board[column][row].Character)
                {
                    case 219:
                        RecordHit();
                        break;
                    default:
                        switch (Renderer.Board[column][row].Character)
                        {
                            case 0x18:
                                switch (Renderer.Board[column][row].ForegroundColor)
                                {
                                    case ASCIICellColor.Cyan:
                                        ChangeTime(1);
                                        break;
                                    case ASCIICellColor.Green:
                                        hits++;
                                        break;
                                    case ASCIICellColor.Red:
                                        misses++;
                                        break;
                                }
                                break;
                            case 0x19:
                                switch (Renderer.Board[column][row].ForegroundColor)
                                {
                                    case ASCIICellColor.Cyan:
                                        ChangeTime(-1);
                                        break;
                                    case ASCIICellColor.Green:
                                        hits--;
                                        break;
                                    case ASCIICellColor.Red:
                                        misses--;
                                        break;
                                }
                                break;
                            case 0xac:
                                switch (Renderer.Board[column][row].ForegroundColor)
                                {
                                    case ASCIICellColor.Cyan:
                                        ChangeTime(-3 * time / 4);
                                        break;
                                    case ASCIICellColor.Green:
                                        hits /= 4;
                                        misses /= 4;
                                        break;
                                    case ASCIICellColor.Red:
                                        break;
                                }
                                break;
                            case 0xab:
                                switch (Renderer.Board[column][row].ForegroundColor)
                                {
                                    case ASCIICellColor.Cyan:
                                        ChangeTime(-time / 2);
                                        break;
                                    case ASCIICellColor.Green:
                                        hits /= 2;
                                        break;
                                    case ASCIICellColor.Red:
                                        misses /= 2;
                                        break;
                                }
                                break;
                            case 0x30:
                                switch (Renderer.Board[column][row].ForegroundColor)
                                {
                                    case ASCIICellColor.Cyan:
                                        ChangeTime(-time);
                                        break;
                                    case ASCIICellColor.Green:
                                        hits = 0;
                                        break;
                                    case ASCIICellColor.Red:
                                        misses = 0;
                                        break;
                                }
                                break;
                            case 0x32:
                                switch (Renderer.Board[column][row].ForegroundColor)
                                {
                                    case ASCIICellColor.Cyan:
                                        ChangeTime(time);
                                        break;
                                    case ASCIICellColor.Green:
                                        hits *= 2;
                                        break;
                                    case ASCIICellColor.Red:
                                        misses *= 2;
                                        break;
                                }
                                break;
                            case 0x34:
                                switch (Renderer.Board[column][row].ForegroundColor)
                                {
                                    case ASCIICellColor.Cyan:
                                        ChangeTime(time * 3);
                                        break;
                                    case ASCIICellColor.Green:
                                        hits *= 4;
                                        break;
                                    case ASCIICellColor.Red:
                                        misses *= 4;
                                        break;
                                }
                                break;
                        }
                        RecordMiss();
                        break;
                }
            }
            return true;
        }

        public override bool OnMessage(MessageBase theMessage)
        {
            if (theMessage.MessageId == CTYBStateMachine.MSGID_MouseDown)
            {
                MessageWithPayload<MouseButtonEventArgs> message = theMessage as MessageWithPayload<MouseButtonEventArgs>;
                return OnMouseDown(message.Payload);
            }
            else if (theMessage.MessageId == CTYBStateMachine.MSGID_Draw)
            {
                OnDraw();
                return true;
            }
            else
            {
                return base.OnMessage(theMessage);
            }
        }
    }
}
